#ifndef PACKET_BLOB_HPP
#define PACKET_BLOB_HPP

#include <cstdint>
#include <cstddef>
#include <cstring>
#include <string>
#include <memory>
#include <limits>

/**
 * @file PacketBlob.hpp
 * @brief “压缩视频包 + 元数据”的最小承载单元。**不依赖 FFmpeg 头文件**，便于客户端/服务端共同包含。
 *
 * 设计要点：
 *  - data/extradata 使用 std::shared_ptr<uint8_t[]> 托管（深拷贝，跨线程安全，支持多消费者共享底层缓冲）；
 *  - 变量注释遵循“先解释是什么，再列举可能值”的风格；
 *  - time_base = num/den，pts/dts 的单位都是 time_base；换算秒：timestamp_sec = pts * num / den。
 *
 * 建议用法：
 *  - 服务端（或拉流侧）在回调里把 AVPacket + StreamInfo 的关键信息 **拷贝** 进此结构，然后把
 *    `std::shared_ptr<PacketBlob>` 放入并发队列；
 *  - 传输时用：Header(4字节 JSON长度, 小端) + JSON(元数据, 含 data_size) + RawBinary(data)；
 *  - 客户端收到后，根据 JSON 初始化/更新解码器，再用紧随其后的 RawBinary 作为 AVPacket->data 解码。
 */
struct PacketBlob {
    //==================== 常量：未知时间戳哨兵 ====================
    /**
     * @brief PTS/DTS 未知时的哨兵值。
     * 说明：不用 INT64_MIN 避免与某些库内部最小值混淆。
     */
    static constexpr int64_t kNoTimestamp = (std::numeric_limits<int64_t>::min)() + 1;

    //==================== 源识别 / 跟踪 ====================
    /**
     * @brief 源标识：用于区分多路流。
     * 可能值：任意字符串，如 "cam01"、"fileA"、"rtsp://...#0"；未知为空字符串。
     */
    std::string source_id;

    /**
     * @brief 包的发送序号（单调递增）。
     * 可能值：>=0；用于诊断丢包/乱序；未知为 0。
     */
    int64_t seq = 0;

    //==================== 编解码器与流信息 ====================
    /**
     * @brief 编解码器“整数 ID”（不使用 FFmpeg 的枚举，便于无依赖传递）。
     * 可能值：>=0 有效；未知为 0。
     */
    int32_t codec_id = 0;

    /**
     * @brief 编解码器短名。
     * 例如："h264"、"hevc"、"mpeg4"；未知为空。
     */
    std::string codec_name;

    /**
     * @brief 编解码器长名（可读性更好）。
     * 例如："H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10"；未知为空。
     */
    std::string codec_long_name;

    /**
     * @brief 时间基（分子）。
     * 作用：timestamp_sec = pts * time_base_num / time_base_den。
     * 可能值：>0；未知时建议 1。
     */
    int32_t time_base_num = 1;

    /**
     * @brief 时间基（分母）。
     * 可能值：>0；未知时建议 1。
     */
    int32_t time_base_den = 1;

    /**
     * @brief 分辨率宽。
     * 可能值：>=0；未知为 0（可由首帧解析后更新）。
     */
    int32_t width = 0;

    /**
     * @brief 分辨率高。
     * 可能值：>=0；未知为 0（可由首帧解析后更新）。
     */
    int32_t height = 0;

    /**
     * @brief 参考帧率（双精度）。
     * 作用：仅作日志/监控/参考；实际时序以 PTS 为准。
     * 可能值：>=0；未知为 0.0。
     */
    double fps = 0.0;

    /**
     * @brief 参考比特率（bit/s）。
     * 可能值：>=0；未知为 0。
     */
    int64_t bit_rate = 0;

    /**
     * @brief 像素格式名（容器/探测标注；压缩流常为 "yuv420p" 或未知）。
     * 可能值：字符串；未知为空。
     */
    std::string pix_fmt_name;

    //==================== 包级元数据 ====================
    /**
     * @brief 显示时间戳（单位：time_base）。
     * 可能值：kNoTimestamp 表示未知。
     */
    int64_t pts = kNoTimestamp;

    /**
     * @brief 解码时间戳（单位：time_base）。
     * 可能值：kNoTimestamp 表示未知。
     */
    int64_t dts = kNoTimestamp;

    /**
     * @brief 包持续时长（单位：time_base）。
     * 可能值：>=0；未知为 0（可由 avg_frame_rate 估算）。
     */
    int32_t duration = 0;

    /**
     * @brief 容器内偏移（字节）。
     * 可能值：>=0；未知为 -1。
     */
    int64_t pos = -1;

    /**
     * @brief 是否关键帧（IDR/KEY）。
     * 可能值：true/false。
     */
    bool is_keyframe = false;

    //==================== 附加数据（SPS/PPS/VPS） ====================
    /**
     * @brief 编解码附加数据的拥有者（共享只读）。
     * 典型内容：H.264 的 SPS/PPS，H.265 的 VPS/SPS/PPS 等。
     * 说明：建议仅在连接初期或变更时下发，不必每包携带。
     */
    std::shared_ptr<uint8_t[]> extradata_ptr;

    /**
     * @brief 附加数据大小（字节）。
     * 可能值：>=0。
     */
    int32_t extradata_size = 0;

    //==================== 压缩数据本体 ====================
    /**
     * @brief 压缩包体（Annex-B/AVCC，建议服务端统一为 Annex-B）。
     * 用途：客户端构造 AVPacket->data 并投喂解码器。
     */
    std::shared_ptr<uint8_t[]> data_ptr;

    /**
     * @brief 压缩数据大小（字节）。
     * 可能值：>=0；0 表示空包（仅信令或 flush）。
     */
    int32_t data_size = 0;

    //==================== 便捷方法 ====================
    /**
     * @brief 安全设置时间基（防止外部传入非法值）
     */
    void SetTimeBase(int32_t num, int32_t den) {
        time_base_num = (num > 0 ? num : 1);
        time_base_den = (den > 0 ? den : 1);
    }

    /**
     * @brief 深拷贝压缩数据到 data_ptr（会覆盖旧内容）
     */
    void DeepCopyData(const uint8_t* src, int32_t size) {
        if (!src || size <= 0) { data_ptr.reset(); data_size = 0; return; }
        std::shared_ptr<uint8_t[]> buf(new uint8_t[size], std::default_delete<uint8_t[]>());
        std::memcpy(buf.get(), src, static_cast<size_t>(size));
        data_ptr = std::move(buf);
        data_size = size;
    }

    /**
     * @brief 深拷贝附加数据到 extradata_ptr（会覆盖旧内容）
     */
    void DeepCopyExtra(const uint8_t* src, int32_t size) {
        if (!src || size <= 0) { extradata_ptr.reset(); extradata_size = 0; return; }
        std::shared_ptr<uint8_t[]> buf(new uint8_t[size], std::default_delete<uint8_t[]>());
        std::memcpy(buf.get(), src, static_cast<size_t>(size));
        extradata_ptr = std::move(buf);
        extradata_size = size;
    }

    /**
     * @brief 把 pts 换算为秒（double）；若未知或 time_base 非法返回负数。
     */
    double PtsSeconds() const {
        if (pts == kNoTimestamp) return -1.0;
        if (time_base_num <= 0 || time_base_den <= 0) return -1.0;
        return static_cast<double>(pts) * (static_cast<double>(time_base_num) / static_cast<double>(time_base_den));
    }

    /**
     * @brief 把 dts 换算为秒（double）；若未知或 time_base 非法返回负数。
     */
    double DtsSeconds() const {
        if (dts == kNoTimestamp) return -1.0;
        if (time_base_num <= 0 || time_base_den <= 0) return -1.0;
        return static_cast<double>(dts) * (static_cast<double>(time_base_num) / static_cast<double>(time_base_den));
    }
};

#endif // PACKET_BLOB_HPP
